package com.suduku.calc;

import com.suduku.entity.Box;
import com.suduku.entity.Sudo;
import com.suduku.calc.enums.CalcEnum;
import com.suduku.listener.SudoListener;
import lombok.Data;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 基础解题方法 <br/>
 *
 * @author chena
 */
@Data
public abstract class AbstractCalc {

    private Sudo sudo;

    /**
     * 功能描述: 实例化 <br/>
     *
     * @param clazz AbstractCalc子类
     * @return "com.suduku.calc.AbstractCalc"
     */
    public static AbstractCalc getInstance(Class<? extends AbstractCalc> clazz) {
        try {
            return clazz.newInstance();
        } catch (Exception e) {
            throw new RuntimeException("实例化异常：" + e.getMessage());
        }
    }

    /**
     * 功能描述: 计算 <br/>
     *
     * @return "com.suduku.calc.enums.CalcResultEnum"
     */
    public boolean calculate() {
        getListener().useCalc(this);
        // 解题
        Box box = solve();
        if (box != null) {
            // 刷新
            this.sudo.refreshOtherBox(box);
            if (box.isBlank()) {
                // 如果没有得到结果，则重复执行
                calculate();
            }
            return true;
        }
        return false;
    }

    /**
     * 功能描述: 改变监听 <br/>
     *
     * @param clearBox 被清理的单元格
     * @param boxes 确定被清理的单元格
     * @param ns 清理的候选值
     */
    protected void change(Box clearBox, List<Box> boxes, Integer... ns) {
        getListener().change(clearBox, boxes, getBoxList(), ns);
    }

    public Box calcSolve() {
        Box box = solve();
        if(box != null) {
            getListener().useCalc(this);
        }
        return box;
    }

    /**
     * 功能描述: 解题方法 <br/>
     *
     * @return "com.suduku.entity.Box"
     */
   abstract Box solve();

    /**
     * 功能描述: 算法枚举 <br/>
     *
     * @return "com.suduku.calc.enums.CalcEnum"
     */
    public CalcEnum getCalcEnum() {
        return CalcEnum.indexOf(this.getClass());
    }

    /**
     * 功能描述: 方便使用，减少算法实现中的获取变量太长的写法 <br/>
     *
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getBoxList() {
        return this.sudo.getBoxList();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "com.suduku.listener.SudoListener"
     */
    protected SudoListener getListener() {
        return this.sudo.getListener();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "java.util.Map<java.lang.Integer,java.util.List<com.suduku.entity.Box>>"
     */
    protected Map<Integer, List<Box>> getXMap() {
        return this.sudo.getXMap();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "java.util.Map<java.lang.Integer,java.util.List<com.suduku.entity.Box>>"
     */
    protected Map<Integer, List<Box>> getYMap() {
        return this.sudo.getYMap();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "java.util.Map<java.lang.Integer,java.util.List<com.suduku.entity.Box>>"
     */
    protected Map<Integer, List<Box>> getGMap() {
        return this.sudo.getGMap();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "java.util.Set<java.util.Map.Entry<java.lang.Integer,java.util.List<com.suduku.entity.Box>>>"
     */
    protected Set<Map.Entry<Integer, List<Box>>> getXentries() {
        return getXMap().entrySet();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "java.util.Set<java.util.Map.Entry<java.lang.Integer,java.util.List<com.suduku.entity.Box>>>"
     */
    protected Set<Map.Entry<Integer, List<Box>>> getYentries() {
        return getYMap().entrySet();
    }

    /**
     * 功能描述: 方便使用 <br/>
     *
     * @return "java.util.Set<java.util.Map.Entry<java.lang.Integer,java.util.List<com.suduku.entity.Box>>>"
     */
    protected Set<Map.Entry<Integer, List<Box>>> getGentries() {
        return getGMap().entrySet();
    }

    /**
     * 功能描述: 方便使用，获取当前单元格所在行的单元格集合 <br/>
     *
     * @param box 单元格
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getXList(Box box) {
        return getXMap().get(box.getX());
    }

    /**
     * 功能描述: 方便使用，获取当前单元格所在行的单元格集合 <br/>
     *
     * @param x 行坐标
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getXList(Integer x) {
        return getXMap().get(x);
    }

    /**
     * 功能描述: 方便使用，获取当前单元格所在列的单元格集合 <br/>
     *
     * @param box 单元格
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getYList(Box box) {
        return getYMap().get(box.getY());
    }

    /**
     * 功能描述: 方便使用，获取当前单元格所在列的单元格集合 <br/>
     *
     * @param y 列坐标
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getYList(Integer y) {
        return getYMap().get(y);
    }

    /**
     * 功能描述: 方便使用，获取当前单元格所在宫的单元格集合 <br/>
     *
     * @param box 单元格
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getGList(Box box) {
        return getGMap().get(box.getG());
    }

    /**
     * 功能描述: 方便使用，获取当前单元格所在宫的单元格集合 <br/>
     *
     * @param g 宫坐标
     * @return "java.util.List<com.suduku.entity.Box>"
     */
    protected List<Box> getGList(Integer g) {
        return getGMap().get(g);
    }

    /**
     * 功能描述: 通过x，y坐标，获取单元格 <br/>
     *
     * @param x 横坐标
     * @param y 纵坐标
     * @return "com.suduku.entity.Box"
     */
    protected Box getBoxByXY(int x, int y) {
        return getBoxList().stream().filter(b -> b.getX() == x && b.getY() == y).findAny().orElse(null);
    }

}
